package cn.kzgg.basic.service.impl;

import cn.kzgg.basic.constants.BaseConstant;
import cn.kzgg.basic.dto.RegisterDto;
import cn.kzgg.basic.exception.BusinessException;
import cn.kzgg.basic.service.IVerifyCodeService;
import cn.kzgg.basic.util.StrUtils;
import cn.kzgg.basic.util.VerifyCodeUtils;
import cn.kzgg.user.domain.User;
import cn.kzgg.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    /**
     * 判断图片验证
     *
     * @param key
     * @return
     */
    @Override
    public String imageCode(String key) {
        //1.判断key不为空
        if (!StringUtils.hasLength(key)) {
            throw new BusinessException("key不能为空");
        }
        //2.使用UUID生成一个图片验证码的值,每次都是新生的，如果前面有的话直接覆盖
        String code = StrUtils.getComplexRandomString(4);
        //3.把验证码的值存储到Redis,以前台传入的key作为key
        redisTemplate.opsForValue().set(
                key,//前端传回来的UUID
                code,//生成的图片验证码
                5,
                TimeUnit.MINUTES);
        //4.把验证码的值合并到图片
        //5.把图片使用Base64编码
        //6.返回base64编码的字符串
        return VerifyCodeUtils.VerifyCode(100, 40, code);
    }

    /**
     * 短信验证
     *
     * 一：校验
     * 1.空校验
     * 2.校验图形验证码，根据imageCodeKey从redis获取图形验证码
     * 。获取不到 图形验证码过期，重新获取
     * 。获取到了，比对图形验证码是否正确
     * - 不正确，提示输入图形验证码错误
     * - 正确，往下走
     * 3.校验手机号是否注册过了
     * 。注册过了，滚去登录
     * 。没有注册过，往下走
     * 二：短信验证码逻辑
     * 1.根据手机号拼接key，159:register，从redis获取曾今可能发送的短信验证码
     * 1.1 获取到了
     * 1.1.1 校验是否过了一分钟重发时间 value  9527:232468742341657213
     * 。小于一分钟  哥屋恩
     * 。大于一分中 （还没有到3分钟，验证码还有效），
     * 使用还没过期的验证码，刷新过期时间
     * 1.2 获取不到
     * 1.2.1.生成新的短信验证码
     * <p>
     * 3.存储redis 设置一个过期时间
     * 4.发送短信
     *
     * @param dto
     */
    @Override
    public void smsCode(RegisterDto dto) {
        String phone = dto.getPhone();
        String imageCodeKey = dto.getImageCodeKey();
        String imageCodeValue = dto.getImageCodeValue();
        //1.空校验
        if (StringUtils.isEmpty(phone)
                || StringUtils.isEmpty(imageCodeKey)
                || StringUtils.isEmpty(imageCodeValue)) {
            throw new BusinessException("参数异常");
        }

        //2.校验图形验证码，根据imageCodeKey从redis中获取图形验证码
        Object imgCodeTmp = redisTemplate.opsForValue().get(imageCodeKey);
        //2.1 获取不到--说明过期，提示重新获取
        if (imgCodeTmp == null) {
            throw new BusinessException("验证码失效，请重新获取");
        }
        //2.2.获取到了，校验输入的是否正确（不要区分大小写）
        if(!imgCodeTmp.toString().equalsIgnoreCase(imageCodeValue)){//不正确
            //2.2.1.错误：提示错误
            throw new BusinessException("验证码错误");
        }//2.2.2.正确：往下执行

        //3.校验电话是否注册过
        User userTmp = userMapper.loadByPhone(phone);
        //3.1.注册过：提示直接登录
        if(userTmp!=null){
            throw new BusinessException("该用户已注册请直接登录");
        }//3.2.没有注册过：往下进行验证

        //2.短信验证逻辑：
        //2.1.根据手机号拼接key：183+register，从redis中获取曾经可能发送的短信验证码
        String key = BaseConstant.RegisterConstant.REGISTER_SMS_PREFIX + phone;
        //相当于     验证码：当前毫秒时间
        Object smsTmp = redisTemplate.opsForValue().get(key);
        //2.1.1.获取到了
        String sms=null;
        if(smsTmp!=null){
            //2.1.1.1.判断是否超过一分钟重发时间:当前时间-获取到的时间
            Long oldTime = Long.valueOf(smsTmp.toString().split(":")[1]);
            if(System.currentTimeMillis()-oldTime<=60*1000){
                //2.1.1.1.1.没有超过说明有人恶意调后端接口，骂！！
                throw new BusinessException("我@@@%#%#￥@%#%你");
            }
            //2.1.1.1.2.超过一分钟没超过3分钟说明验证码还有效，并刷新过期时间(超过3分钟就会从redis中清除缓存，相当于没获取到)
            sms = smsTmp.toString().split(":")[0];

        }else {
            //2.1.2.没获取到
            //生成新的验证码
            sms = StrUtils.getComplexRandomString(4);
        }
        //3.存储redis设置一个过期时间
        String smsValue = sms + ":" + System.currentTimeMillis();

        redisTemplate.opsForValue().set(key,smsValue,3,TimeUnit.MINUTES);
        //4.发送短信
        //SmsUtils.sendSms(phone,"亲，您的验证码是："+smsCode+"。请在3分钟内使用！！");
        System.out.println("您的验证码是："+smsValue+"，请在3分支内使用");
    }
}
